/******************************************************************************
 * This file is part of project ORCA. More information on the project
 * can be found at the following repositories at GitHub's website.
 *
 * http://https://github.com/andersondomingues/orca-sim
 * http://https://github.com/andersondomingues/orca-software
 * http://https://github.com/andersondomingues/orca-mpsoc
 * http://https://github.com/andersondomingues/orca-tools
 *
 * Copyright (C) 2018-2020 Anderson Domingues, <ti.andersondomingues@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
******************************************************************************/
#ifndef ORCASIM_MODELING_INCLUDE_SIGNALSET_HPP_
#define ORCASIM_MODELING_INCLUDE_SIGNALSET_HPP_

// lib dependent includes
#include <stdint.h>
#include <iostream>
#include <vector>
#include <string>

// api includes
#include "UntimedModel.hpp"
#include "MemoryType.hpp"

using orcasim::base::UntimedModel;

namespace orcasim::modeling {

/**
 * The SignalSet class models a generic set of busses of type T.
 * */
template <typename T>
class SignalSet : public UntimedModel {
 private:
    /** number of signals in the set. Cannot be changed runtime. **/
    uint32_t _num_signals;

    /** memory position of the first signal. Other signals' positions
     * are generated by incrementing this index by sizeof(T)**/
    MemoryAddr  _mem_addr;
    MemoryType* _mem_ptr;

    /** a pointer to the first signal. An array will be instantiated 
     * to store signals in that pointer. **/
    Signal<T>** _signals;

    /** an optional name to identify this model during runtime */
    std::string _t_name;

 public:
    /**
     * @brief Constructor. Creates a new SignalSet.
     * @param name An arbitrary name for the instance.
     * @param nsig Number of signals to be created
     */
    SignalSet(std::string name, uint32_t nsig);

    /**
     * @brief Destructor.
     * @note DO NOT free _t_ptr by any means as this pointer must be 
     * freed by the class which allocated the space. 
     */
    ~SignalSet();

    /**
     * @brief Get the a signal from the set. 
     * @param index The identifier of the signal to be returned.
     * @return A pointer to the requested signal.
     */
    Signal<T>* GetSignal(uint32_t index);

    /**
     * @brief Maps the signal set to a given memory address. Signals'
     * addresses are generated by incrementing the address of the 
     * first signal.
     * @param mptr Pointer to the memory location to be mapped
     * @param addr Address to the set to the first signals
     */
    void MapTo(MemoryType* mptr, MemoryAddr addr);
};

// Some of the most used instances. More can be added later.
// for larger data size, consider using a Memory instead.
template class SignalSet<bool>;  // wire
template class SignalSet<uint8_t>;   // mem word
template class SignalSet<uint16_t>;  // dmni/noc word
template class SignalSet<uint32_t>;  // proc word
template class SignalSet<uint64_t>;  // double word
template class SignalSet<int8_t>;   // mem word
template class SignalSet<int16_t>;  // dmni/noc word
template class SignalSet<int32_t>;  // proc word
template class SignalSet<int64_t>;  // double word

}  // namespace orcasim::modeling
#endif  // ORCASIM_MODELING_INCLUDE_SIGNALSET_HPP_
